home *** CD-ROM | disk | FTP | other *** search
- /*
- GrepIO - routines for treating TEXT or WORD (MacWrite)
- files as a stream of characters or lines, and for output file
- setup and termination.
- */
-
- # include <FileMgr.h>
- # include <StdFilePkg.h>
- # include "Grep.h"
-
-
- # define bufSize 1024 /* input buffer size */
- # define lineLen 65 /* output line len before break */
-
-
- typedef Byte ByteBuf[];
-
-
- typedef struct
- {
- int version;
- int paraOffset;
- int paraCount;
- } DocInfo3;
-
- typedef struct
- {
- int paraType;
- int paraLen;
- } ParaInfo3;
-
-
- typedef struct
- {
- long iArrayPos;
- int iArrayLen;
- } DocInfo6;
-
-
- typedef struct /* information array element */
- {
- int height;
- int pagePos;
- long **paraHand;
- union
- {
- Byte st; /* first byte is status */
- long pos;
- } stPos;
- int dataLength;
- int formats;
- } ParaInfo6, InfoArray[];
-
-
-
- SFReply outReply; /* output file */
- SFReply theStream; /* SFGetFile reply record */
- Boolean streamOpen = false; /* whether stream currently open */
- int streamType; /* file type of stream */
- int f; /* input file reference number */
-
-
- /* vars needed for TEXT stream only */
-
- char filBuf[bufSize]; /* file buffer */
- long fLen;
- int fChars;
-
- /* vars needed for WORD stream only */
-
- ByteBuf **paraBuf = nil;
- InfoArray **infoHand = nil;
- Boolean compressed;
- Boolean inPara;
- int nParas; /* number of paragraphs */
- int paraNum; /* current paragraph number */
- int pIndex; /* index into paragraph */
- int pChars; /* number of chars extracted from paragraph */
- int pLen; /* number of chars in paragraph */
-
- /* decompression variables */
-
- Boolean firstHalf; /* which half of current index char */
- Boolean needNib; /* true = 2nd nibble needed for ascii */
- Boolean nextAsc; /* true = two nibbles needed */
- Byte lastNib; /* holds last nibble */
-
- /* miscellaneous */
-
- Point dlogWhere = { 70 /* = y */, 100 /* = x */ };
- OSType type[2] = { 'WORD', 'TEXT' };
-
-
- MyFRead (p, amount)
- Ptr p;
- long amount;
- {
- (void) FSRead (f, &amount, p);
- }
-
- MyFSeek (pos)
- long pos;
- {
- (void) SetFPos (f, fsFromStart, pos);
- }
-
-
- /*
- _FSOpen - like FSOpen, but has open mode parameter.
-
- CloseStream - close current stream, if one is open. Releases any
- heap storage currently used, if stream is WORD type.
-
- OpenStream - open 'TEXT' or 'WORD' stream.
- Return noErr if file opened OK, fnOpnErr or mFulErr if not.
- if OK, set fileOpen true.
- */
-
-
- OSErr _FSOpen (fName, vRefNum, refNum, mode)
- StringPtr fName;
- int vRefNum;
- int *refNum;
- int mode;
- {
- ParamBlockRec p;
- register OSErr result;
-
- p.ioParam.ioNamePtr = fName;
- p.ioParam.ioVRefNum = vRefNum;
- p.ioParam.ioPermssn = mode;
- p.ioParam.ioVersNum = 0;
- p.ioParam.ioMisc = 0;
- result = PBOpen (&p, false);
- *refNum = p.ioParam.ioRefNum;
- return (result);
- }
-
-
- CloseStream ()
- {
- if (streamOpen)
- {
- (void) FSClose (f);
- /*(void) FlushVol (nil, theStream.vRefNum);*/
- streamOpen = false;
- if (paraBuf != nil)
- {
- DisposHandle (paraBuf);
- paraBuf = nil;
- }
- if (infoHand != nil)
- {
- DisposHandle (infoHand);
- infoHand = nil;
- }
- }
- }
-
-
- OSErr OpenStream ()
- {
- DocInfo3 docInfo3;
- DocInfo6 docInfo6;
- register OSErr result = fnOpnErr;
- register int curRes;
-
- CloseStream (); /* close any currently open stream */
-
- curRes = CurResFile ();
- UseResFile (0);
- SFGetFile (dlogWhere, "\p", nil, 2, &type, nil, &theStream);
- UseResFile (curRes);
- Update (); /* refresh screen immediately */
- if (theStream.good)
- {
- if (_FSOpen (theStream.fName, theStream.vRefNum,
- &f, fsRdPerm) == noErr)
- {
- streamOpen = true;
- result = noErr;
- }
- }
-
- if (result == noErr) /* so far, so good */
- {
- if (theStream.fType == 'TEXT')
- {
- streamType = text;
- fChars = 0; /* set these to trigger a read on the first */
- fLen = 0; /* call to StreamGetC() */
- }
- else /* must be WORD file - determine version */
- {
- paraBuf = (ByteBuf **) NewHandle (0L);
- MyFRead (&docInfo3, (long) sizeof (DocInfo3));
-
- if (docInfo3.version == 3) /* MacWrite 2.2 file */
- {
- streamType = mwrt3;
- nParas = docInfo3.paraCount;
- MyFSeek ((long) docInfo3.paraOffset);
- }
- else if (docInfo3.version == 6) /* MacWrite 4.5 file */
- {
- streamType = mwrt6;
- MyFSeek (264L); /* 252 + 12 */
- MyFRead (&docInfo6, (long) sizeof (DocInfo6));
- MyFSeek (docInfo6.iArrayPos);
- infoHand = (InfoArray **) NewHandle (docInfo6.iArrayLen);
- if (infoHand == nil)
- {
- CloseStream ();
- result = mFulErr;
- }
- else
- {
- HLock (infoHand);
- MyFRead (*infoHand, (long) docInfo6.iArrayLen);
- HUnlock (infoHand);
- nParas = docInfo6.iArrayLen / sizeof (ParaInfo6);
- }
- }
- else
- {
- CloseStream ();
- Alarm ("\pFile created by unsupported MacWrite version");
- result = fnOpnErr;
- }
- paraNum = -1;
- inPara = false; /* not in any paragraph yet */
- }
- }
- return (result);
- }
-
-
- Boolean GetStream ()
- {
-
- if (OpenStream () != noErr)
- return (false);
- DisplayString (theStream.fName);
- DisplayString ("\p (");
- DisplayString (streamType == text ? "\pText" : "\pMacWrite");
- DisplayString ("\p file)\r");
- return (true);
- }
-
-
- /*
- _Decompress takes a nibble at a time of compressed text. If more
- nibbles are needed to complete the next character, return -1, else
- returns the character.
- */
-
- _Decompress (b)
- Byte b;
- {
- register int result = -1;
-
- if (needNib) /* Low half of ascii nibble is needed. */
- {
- needNib = false;
- result = lastNib | b; /* Put the two halves together */
- }
- else if (nextAsc) /* Two nibbles are needed */
- {
- nextAsc = false;
- lastNib = b << 4; /* Save this one as the high nibble */
- needNib = true; /* Need one more nibble */
- }
- else if (b == 15) /* Nibble of 15 means the next char is ascii */
- nextAsc = true;
- else /* Add the nibble value to the English decompression */
- /* key (saved as Resource Type 'STR ' 700 in file) */
- /* to get the proper character */
- {
- result = " etnroaisdlhcfp" [b]; /* note: C string */
- }
- return (result);
- }
-
-
- Boolean ReadParaBuf ()
- {
- SetHandleSize (paraBuf, pLen); /* make big enough */
- if (MemError () != noErr)
- {
- Alarm ("\pCan't read paragraph buffer");
- paraNum = nParas; /* force stream close and exit of GetC loop */
- return (false);
- }
- HLock (paraBuf);
- MyFRead (*paraBuf, (long) pLen);
- HUnlock (paraBuf);
- return (true);
- }
-
-
- WordStreamGetC () /* return -1 on EOF */
- {
- register int c;
- register int result;
- ParaInfo3 paraInfo3;
-
- if (!inPara) /* must read in next paragraph */
- {
- for (;;)
- {
- if (++paraNum >= nParas)
- {
- CloseStream ();
- return (-1);
- }
- if (streamType == mwrt3)
- {
- MyFRead (¶Info3, (long) sizeof (ParaInfo3));
- pLen = paraInfo3.paraLen;
- if (ReadParaBuf () == false)
- continue;
- if (paraInfo3.paraType != 1)
- {
- continue; /* not text */
- }
- /* adding two skips length word */
- if ((pLen = ((int *) **paraBuf)[0] + 2) == 2)
- continue; /* empty paragraph */
- pChars = 2;
- compressed = false;
- inPara = true;
- break;
- }
- else /* mwrt6 */
- {
- if ((**infoHand)[paraNum].height <= 0)
- {
- continue; /* not text */
- }
-
- /*
- Seek to this paragraph's data (must mask the high byte to get the
- correct value). Move to the paragraph, get its length, make
- the pointer big enough, and read it in. (skip to next para if this
- one is empty, though.)
- compressed will be set true if the paragraph is compressed.
- */
-
- MyFSeek ((**infoHand)[paraNum].stPos.pos & 0x00FFFFFF);
- MyFRead (&pLen, (long) sizeof (int)); /* get length */
- if (pLen == 0)
- {
- continue; /* empty para - skip */
- }
- if (ReadParaBuf () == false)
- continue;
- compressed = ((**infoHand)[paraNum].stPos.st >> 3) & 1;
- inPara = true;
- nextAsc = false;
- needNib = false;
- pIndex = 0; /* index into current paragraph */
- pChars = 0; /* chars extracted from current paragraph */
- firstHalf = true; /* use first half of current index char */
- break;
- }
- }
- }
-
- /*
- At this point, know either that we have a new non-empty paragraph, or
- are still in the previous one.
- */
-
- if (!compressed) /* uncompressed */
- {
- c = (**paraBuf)[pChars];
- }
- else
- {
- do
- {
- c = (**paraBuf)[pIndex];
- if (firstHalf)
- {
- c = _Decompress (((Byte) c) >> 4);
- }
- else
- {
- c = _Decompress ((Byte) (c & 0x0f));
- ++pIndex; /* go to next char at next index */
- }
- firstHalf = !firstHalf;
- } while (c == -1);
- }
- if (++pChars >= pLen) /* see if need new paragraph next time */
- inPara = false;
- return (c);
- }
-
-
- /*
- StreamGetC - get character from stream.
- */
-
- StreamGetC ()
- {
-
- if (!streamOpen)
- return (-1);
-
- if (streamType != text)
- return (WordStreamGetC ());
-
- if (fChars >= fLen) /* need to read in a new block */
- {
- fLen = bufSize;
- (void) FSRead (f, &fLen, filBuf);
- if (fLen == 0)
- {
- CloseStream ();
- return (-1);
- }
- fChars = 0;
- }
- return (filBuf[fChars++]);
- }
-
-
- /*
- StreamGetS - get string from stream.
-
- Returns nil if no string obtained, otherwise a pointer to the argument.
- */
-
- StringPtr StreamGetS (s)
- register StringPtr s;
- {
- register int c;
- register StringPtr result = nil;
-
- s[0] = 0; /* clear string */
- while ((c = StreamGetC ()) != -1)
- {
- result = s; /* got something, so StreamGetS succeeds */
- if (c == '\r' || (s[0] > lineLen && c == ' '))
- break;
- s[++s[0]] = c; /* add char to end */
- }
- return (result);
- }
-
-
-
- FileOutput ()
- {
- FInfo f;
- long pos;
- register int curRes;
-
- if (fileOpen) /* close it */
- {
- fileOpen = false;
- (void) GetFPos (outFile, &pos);
- (void) SetEOF (outFile, pos);
- (void) FSClose (outFile);
- (void) FlushVol (nil, outReply.vRefNum);
- SetItem (theMenu, saveOutput, "\pSave Output...");
- }
- else
- {
- curRes = CurResFile ();
- UseResFile (0);
- SFPutFile (dlogWhere, "\pWrite To...", "\p", nil, &outReply);
- UseResFile (curRes);
- Update (); /* refresh screen immediately */
- if (outReply.good)
- {
- if (GetFInfo (outReply.fName, outReply.vRefNum, &f) == noErr) /* exists */
- {
- if (f.fdType != 'TEXT')
- {
- Alarm ("\pNot a TEXT File");
- return;
- }
- }
- else /* doesn't exist. create it. */
- {
- if (Create (outReply.fName, outReply.vRefNum,
- 'Grep', 'TEXT') != noErr)
- {
- Alarm ("\pCan't Create");
- return;
- }
- }
-
- if (_FSOpen (outReply.fName, outReply.vRefNum,
- &outFile, fsWrPerm) != noErr)
- Alarm ("\pCan't Open");
- else
- {
- fileOpen = true;
- SetItem (theMenu, saveOutput, "\pStop Saving Output");
- }
- }
- }
- }
-